package nl.jteam.jsa.core;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

/** @author Uri Boness */
public class Page<T> implements ListPage<T> {

    protected final List<T> items;
    private final int index;
    private final int capacity;
    private final int totalItemCount;

    private transient boolean first;
    private transient boolean last;
    private transient boolean single;
    private transient int lastPageIndex;
    private transient int firstItemIndex;
    private transient int lastItemIndex;

    public Page(int index, int maxItems, int totalItemCount) {
        this(new ArrayList<T>(), index, maxItems, totalItemCount);
    }

    public Page(List<T> items, int index, int maxItems, int totalItemCount) {
        this.items = items;
        this.index = index;
        this.capacity = maxItems;
        this.totalItemCount = totalItemCount;
        computePageProperties();
    }

    public Iterator<T> iterator() {
        return items.iterator();
    }

    public List<T> getElements() {
        return Collections.unmodifiableList(items);
    }

    public int getSize() {
        return items.size();
    }


    //============================================== Helper Methods ====================================================

    protected void computePageProperties() {
        lastPageIndex = computeLastPageIndex();
        firstItemIndex = computeFirstItemIndex();
        last = index == lastPageIndex;
        lastItemIndex = computeLastItemIndex(firstItemIndex, last);
        first = index == 0;
        single = last && first;
    }

    protected int computeLastPageIndex() {
        if (totalItemCount == 0) {
            return 0;
        }
        int index = totalItemCount / capacity;
        if (totalItemCount % capacity == 0) {
            index--;
        }
        return index;
    }

    protected int computeFirstItemIndex() {
        return capacity * index;
    }

    protected int computeLastItemIndex(int firstItemIndex, boolean last) {
        if (last) {
            return firstItemIndex + totalItemCount % capacity - 1;
        }
        return firstItemIndex + capacity - 1;
    }

    //============================================== Setter/Getter =====================================================

    public int getIndex() {
        return index;
    }

    public int getCapacity() {
        return capacity;
    }

    public int getListSize() {
        return totalItemCount;
    }

    public boolean isFirst() {
        return first;
    }

    public boolean isLast() {
        return last;
    }

    public boolean isSingle() {
        return single;
    }

    public int getLastPageIndex() {
        return lastPageIndex;
    }

    public int getFirstItemIndex() {
        return firstItemIndex;
    }

    public int getLastItemIndex() {
        return lastItemIndex;
    }

    public boolean isEmpty() {
        return getSize() == 0;
    }
}
